package com.lanyun.web.core.handler;

import com.lanyun.exception.ServiceException;
import com.lanyun.web.bean.Result;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Author Jqcc
 * @Version 1.0
 * @Data 2025/2/14
 * <p>
 * 全局异常处理器
 */
@RestControllerAdvice
@AllArgsConstructor
public class GlobalExceptionHandler {

    /**
     * 处理业务异常 ServiceException
     *
     * @param ex
     * @return
     */
    @ExceptionHandler(value = ServiceException.class)
    public Result<?> serviceExceptionHandler(ServiceException ex) {
        return Result.fail(ex.getCode(), ex.getMessage());
    }


    /**
     * 处理表单绑定异常（@Validated 触发的校验异常）
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Map<String, String>> handleBindException(BindException ex) {
        Map<String, String> errors = new HashMap<>();
        List<FieldError> fieldErrors = ex.getFieldErrors();
        for (FieldError fieldError : fieldErrors) {
            errors.put(fieldError.getField(), fieldError.getDefaultMessage());
        }
        return Result.fail(HttpStatus.BAD_REQUEST.value(), "参数校验失败", errors);
    }

    /**
     * 处理请求体绑定异常（@Validated 触发的校验异常）
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Map<String, String>> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getFieldErrors().forEach(fieldError -> {
            errors.put(fieldError.getField(), fieldError.getDefaultMessage());
        });
        return Result.fail(HttpStatus.BAD_REQUEST.value(), "参数校验失败", errors);
    }

    /**
     * 处理参数校验异常（@RequestParam、@PathVariable 触发的校验异常）
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<Map<String, String>> handleConstraintViolationException(ConstraintViolationException ex) {
        Map<String, String> errors = new HashMap<>();
        Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            String field = violation.getPropertyPath().toString();
            String message = violation.getMessage();
            errors.put(field, message);
        }
        return Result.fail(HttpStatus.BAD_REQUEST.value(), "参数校验失败", errors);
    }

    /**
     * 处理请求体缺失异常 (入参类型错误也会走这里)
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handleHttpMessageNotReadableException(HttpMessageNotReadableException ex) {
        return Result.fail(HttpStatus.BAD_REQUEST.value(), "请求体缺失，请检查请求参数");
    }


}
